package com.ufo.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;

import java.net.SocketAddress;
import java.nio.charset.Charset;
import java.util.Date;

public class NettyLaunch {
    public static void main(String[] args){
        EasyBoot();
    }

    private static void EasyBoot() {
        EventLoopGroup bossGroup=new NioEventLoopGroup();
        EventLoopGroup workerGroup=new NioEventLoopGroup();
        try{
            ServerBootstrap bootstrap=new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    //内核会根据somaxconn和backlog的较小值设置accept queue.
                    .option(ChannelOption.SO_BACKLOG,128)//linux默认128
                    .childHandler(new HttpServerInitializer());
            ChannelFuture future=bootstrap.bind(8080).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
class HttpServerInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        System.out.println("开始链接："+socketChannel.localAddress().getHostString()+" port="+socketChannel.localAddress().getPort());
        ChannelPipeline pipeline=socketChannel.pipeline();
        pipeline.addLast(new MyOutBoundServerHandler());
        pipeline.addLast("httpServerCodec",new HttpServerCodec());
        pipeline.addLast(new MyServerHandler());
        pipeline.addLast("httpServerHandler",new HttpServerChannelHandler());
    }
}

//SimpleChannelInboundHandler 可以自动release
class HttpServerChannelHandler extends SimpleChannelInboundHandler<HttpObject>{

    private HttpRequest request;

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        System.out.println("---inbound---");
        if(httpObject instanceof HttpRequest){
            request=(HttpRequest) httpObject;
            request.method();
            String uri= request.uri();
            System.out.println("uri="+uri);
        }
        if(httpObject instanceof HttpContent) {
            HttpContent content = (HttpContent) httpObject;
            ByteBuf byteBuf = content.content();
            System.out.println(byteBuf.toString(CharsetUtil.UTF_8));

            ByteBuf byteBuf2 = Unpooled.copiedBuffer("Hello world", CharsetUtil.UTF_8);
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf2);
            response.headers().add(HttpHeaderNames.CONTENT_TYPE, "text/plain")
                    .add(HttpHeaderNames.CONTENT_LENGTH, byteBuf2.readableBytes());

            channelHandlerContext.writeAndFlush(response);
        }
    }

}
class MyServerHandler extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//        ByteBuf buf = (ByteBuf) msg;
//        byte[] msgByte = new byte[buf.readableBytes()];
//        buf.readBytes(msgByte);
        System.out.println(new Date() + "接收到消息：");
//        System.out.println(new String(msgByte, Charset.forName("GBK")));
        ctx.fireChannelRead(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("---inbound Complete---");
//        ctx.flush();
    }
}

class MyOutBoundServerHandler extends ChannelOutboundHandlerAdapter{

    @Override
    public void read(ChannelHandlerContext ctx) throws Exception {
        System.out.println("---outbound read---");
        super.read(ctx);
    }

    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
        System.out.println("---outbound connection---");
        super.connect(ctx, remoteAddress, localAddress, promise);
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("---outbound write---");
        super.write(ctx, msg, promise);
    }

    @Override
    public void flush(ChannelHandlerContext ctx) throws Exception {
        System.out.println("---outbound flush---");
        super.flush(ctx);
    }
}